// encoding=utf-8

#ifndef __qysciedit__
#define __qysciedit__

#include <Qsci/qsciscintilla.h>

class QSettings;
class QySciEdit;
class QySciLexer;

//! Типы маркеров
struct QySciMarkerType {
	enum {
		Arrow, //!< указатель
		Error, //!< ошибка
		Warning, //!<  предупреждение
		Bookmark //!< закладка
	};
};

/*! \class QyMarginArrow
	\brief Класс для управления маркером.

	При помощи QyMarginArrow реализуется "плавющий" маркер. Т.е. Маркер который свободно перемещается со строки на строки, по воли пользователя =).

	Создавать QyMarginArrow позволено только редактору, в котором будет существовать этот маркер.

*/

class QyMarginArrow {
public:
	int position() const { return p_line; }  //!< строка, на которой расположен маркер

	void setPosition( int line ); //!< переместить маркер на строку
	void setVisible( bool visible ); //!< установить видимость маркера
	void show(); //!< показать маркер
	void hide(); //!< спрятать маркер

private:
	QyMarginArrow( QySciEdit * edit=0, int line=-1 );

	int p_handle, p_line;
	QySciEdit * p_edit;

friend class QySciEdit;
};


/*! \class QySciFindRequest
	\brief Поисковый запрс для редактора.

	Не содержит никакого функционала, создан для удобства.

*/

class QySciFindRequest {
public:
	QySciFindRequest( const QString & text=QString(), bool re=false, bool cs=false, bool wm=false )
		: p_text(text), p_re(re), p_cs(cs), p_wm(wm) {} //!< Конструктор формирующий запрос

	QString text() const { return p_text; } //!< искомый текст
	bool regExp() const { return p_re; } //!< регулярное выражение
	bool caseSensitive() const { return p_cs; } //!< чувствительность к регистру
	bool wordMatches() const { return p_wm; } //!< фраза целиком
	bool isValid() const { return !p_text.isEmpty(); } //!< тест валидностьи

	bool operator == ( const QySciFindRequest & request ) const { //!< оператор сравнения двух запросов

		return p_text == request.p_text &&
			p_re == request.p_re &&
			p_cs == request.p_cs &&
			p_wm == request.p_wm;
	}

private:
	QString p_text;
	bool p_re, p_cs, p_wm;

};

/*! \class QySciEdit
	\brief Текстовый редактор, базирующийся на QScintilla.

	QySciEdit расширяет стандартные возможности QScintilla. Позволяя пользователю сохранять и/или загружать файлы, перекодировать файлы из одной кодировки в другую, осуществлять поиск (поиск организован более удобно и чем в оригенале) и замену текста, оперативно добавлять маркеры и многое другое.

	При открытии файла, QySciEdit ищет в первых 2х строках файла информацию о кодировке файла, при этом строки могут содержать любые символы, информация о кодировке должна имет вид:
	\code
	encoding utf-8
	\endcode

	Фот примеры файлов, инфорация из которых будет извлечена правильно:

	\code
	// ...
	// FileEncoding=utf-8
	...
	\endcode

	\code
	// encoding: utf-8
	...
	\endcode

	Информация о кодировке учитывается и при сохранении файла, т.е. можно менять кодировку файла просто исправив имя кодировки в начале файла.

*/

class QySciEdit : public QsciScintilla {
	Q_OBJECT
public:
	QySciEdit( QWidget * parent=0, const QString & name=QString() ); //!< Конструктор, позволяющий задать имя объекта
	QySciEdit( const QString & fileName, QWidget * parent=0, const QString & name=QString() ); //!< Конструктор, позволяющий задать имя объекта и открыть файл в редакторе
	virtual ~QySciEdit(); //!< диструктор

	QString fileName() const { return p_lastFileName; } //!< имя файла
	QString encodingName() const { return p_encodingName; } //!< имя кодировки
	bool isOpen() const { return p_isOpen; } //!< вернет true если открыт файл
	bool isNew() const { return p_isNew; } //!< вернет true если в этом редакторе файлы еще не открывались
	QyMarginArrow marginArrow() const { return p_marginArrow; } //!< интерфейс правления маркером типа "указатель"
	QyMarginArrow & marginArrow() { return p_marginArrow; } //!< интерфейс правления маркером типа "указатель"
	int line() const; //!< номер строки на которой стоит каретка
	int index() const; //!< номер символа на котором стоит каретка
	int trueLineLength( int line ) const { return text(line).count(); } //!< возвращает правильную длину строки, стандартный метод QsciScintilla::lineLength некоторых версий (у меня такая), возвращает длину строки без учнта юникода в ней
	bool findFirst( const QString & str, bool re=false, bool cs=false, bool wm=false,
		bool wrap=true, bool forward=true, int line=-1, int index=-1, bool show=true ); //!< начать поиск строки в редакторе (параметры wrap,forward и show не учитываются, по умолчанию при поиске они всегда true)
	bool findText( QySciFindRequest request=QySciFindRequest(), int line=-1, int index=-1 ); //!< начать поиск строки в редакторе
	bool findText( const QString & str, bool re=false, bool cs=false, bool wm=false, int line=-1,
		int index=-1 ); //!< начать поиск строки в редакторе
	bool hasTextFind() const { return lastRequest.isValid(); } //!< был ли уже инициализирован поиск
	bool replaceOne( const QString & findText, const QString & replaceText, bool re, bool cs,
		bool wm ); //!< заменить один раз
	bool replaceAll( const QString & findText, const QString & replaceText, bool re, bool cs,
		bool wm ); //!< заменить все
	bool replaceInSelection( const QString & findText, const QString & replaceText, bool re,
		bool cs, bool wm ); //!< заменить все в выделенном

	bool isAutoStripTrailingSpaces() const { return p_autoStripTrailingSpaces; } //!< удаляются ли "лишние" пробелы и табуляции при сохранении

	static QString fileEncoding( const QString & fileName ); //!< извлечь информацию о кодировке из файла

public slots:
	void openFile( const QString & fileName, const QString & encodingName=QString() ); //!< открыть файл
	void openFile( const QString & fileName, int line ); //!< открыть файл на строке
	bool save( QString fileName=QString(), const QString & encodingName=QString() ); //!< сохранить файл
	void addMarker( int line, int markerType ); //!< добавить маркер
	void removeMarkers( int line=-1, int markerType=-1 ); //!< удалить маркеры
	void leftShiftCurrent(); //!< сдвинуть текст влево на один таб
	void foldCurrent(); //!< свернуть текущий блок
	void stripTrailingSpaces(); //!< удалить все "лишниеЭ пробелы и табуляции, лишними считаются пробелы и табы стоящие в конце строки
	void selectAllCurrentLines(); //!< дополнить выделени, т.е. если на данный момент выделена одна строка целиком и вторая на половину, то после вызова данного метода будет выделена и первая и вторая строки целиком
	void setLine( int line ); //!< переместить каре6тку на строку
	void toggleCommentSelectedLines(); //!< закомментировать/раскомментировать текущую строки или выделенные строки
	void setAutoStripTrailingSpaces( bool enabled ) { p_autoStripTrailingSpaces = enabled; } //!< вкл/выкл удаление "лишних" пробелов и табуляций при сохранении

	static void loadSettings( QSettings & settings, const QString & prefix=QString() ); //!< загрузать параметры редактора, метод устарел

signals:
	void encodingChanged( const QString & encodingName ); //!< кодировка файла изменилась
	void fileNameChanged( const QString & fileName ); //!< имя файла изменилось

protected:
	void setEncoding( const QString & encodingName ); // установить кодировку (файл не перкодируется)

private slots:
	void linesCountChanged(); // кол-во строк изменилось

private:
	void init(); // метод инициализирующий объект

	QString p_lastFileName, // имя файла
		p_encodingName; // кодировка
	QySciFindRequest lastRequest; // последний поисковый запрос
	bool p_isOpen, // флаг - файл открыт
		p_isNew, // флаг - файл новый (устарел)
		p_autoStripTrailingSpaces; // флаг - удалять ли при сохранении "лишние" пробелы и табуляции
	QyMarginArrow p_marginArrow; // контроллер маркера "указатель"

};

#endif/*__qysciedit__*/
